﻿using System;
using System.Collections.Generic;
using System.Data;

namespace MyLib {
	/// <summary>
	/// 
	/// </summary>
	public static class DataViewExtensions {
		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="dataTable"></param>
		/// <param name="selector"></param>
		/// <returns></returns>
		public static IEnumerable<T> Select<T>(this DataTable dataTable, Func<DataRow, T> selector) {
			if (dataTable == null)
				yield break;

			foreach (DataRow row in dataTable.Rows) {
				if (row == null)
					continue;

				yield return selector(row);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="dataView"></param>
		/// <param name="selector"></param>
		/// <returns></returns>
		public static IEnumerable<T> Select<T>(this DataView dataView, Func<DataRowView, T> selector) {
			if (dataView == null)
				yield break;

			foreach (DataRowView row in dataView) {
				if (row == null)
					continue;

				yield return selector(row);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="row"></param>
		/// <param name="columnName"></param>
		/// <returns></returns>
		public static T Get<T>(this DataRow row, string columnName) {
			try {
				return (T)Convert.ChangeType(row[columnName], typeof(T));
			} catch (FormatException fe) {
				throw new InvalidOperationException(
					string.Format("Cannot convert row[\"{0}\"] to {1}", columnName, typeof(T)), fe);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="row"></param>
		/// <param name="columnName"></param>
		/// <returns></returns>
		public static T Get<T>(this DataRowView row, string columnName) {
			try {
				return (T)Convert.ChangeType(row[columnName], typeof(T));
			} catch (FormatException fe) {
				throw new InvalidOperationException(
					string.Format("Cannot convert row[\"{0}\"] to {1}", columnName, typeof(T)), fe);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="row"></param>
		/// <param name="columnIndex"></param>
		/// <returns></returns>
		public static T Get<T>(this DataRow row, int columnIndex) {
			try {
				return (T)Convert.ChangeType(row[columnIndex], typeof(T));
			} catch (FormatException fe) {
				throw new InvalidOperationException(
					string.Format("Cannot convert row[{0}] to {1}", columnIndex, typeof(T)), fe);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="row"></param>
		/// <param name="columnIndex"></param>
		/// <returns></returns>
		public static T Get<T>(this DataRowView row, int columnIndex) {
			try {
				return (T)Convert.ChangeType(row[columnIndex], typeof(T));
			} catch (FormatException fe) {
				throw new InvalidOperationException(
					string.Format("Cannot convert row[{0}] to {1}", columnIndex, typeof(T)), fe);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="row"></param>
		/// <param name="columnName"></param>
		/// <returns></returns>
		public static string GetString(this DataRow row, string columnName) {
			return Get<string>(row, columnName);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="row"></param>
		/// <param name="columnName"></param>
		/// <returns></returns>
		public static int GetInt32(this DataRow row, string columnName) {
			return Get<int>(row, columnName);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="row"></param>
		/// <param name="columnName"></param>
		/// <returns></returns>
		public static decimal GetDecimal(this DataRow row, string columnName) {
			return Get<decimal>(row, columnName);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="row"></param>
		/// <param name="columnName"></param>
		/// <returns></returns>
		public static double GetDouble(this DataRow row, string columnName) {
			return Get<double>(row, columnName);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="row"></param>
		/// <param name="columnName"></param>
		/// <returns></returns>
		public static bool GetBoolean(this DataRow row, string columnName) {
			return Get<bool>(row, columnName);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="row"></param>
		/// <param name="columnName"></param>
		/// <returns></returns>
		public static DateTime GetDateTime(this DataRow row, string columnName) {
			return Get<DateTime>(row, columnName);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="row"></param>
		/// <param name="columnIndex"></param>
		/// <returns></returns>
		public static string GetString(this DataRow row, int columnIndex) {
			return Get<string>(row, columnIndex);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="row"></param>
		/// <param name="columnIndex"></param>
		/// <returns></returns>
		public static int GetInt32(this DataRow row, int columnIndex) {
			return Get<int>(row, columnIndex);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="row"></param>
		/// <param name="columnIndex"></param>
		/// <returns></returns>
		public static long GetInt64(this DataRow row, int columnIndex) {
			return Get<long>(row, columnIndex);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="row"></param>
		/// <param name="columnIndex"></param>
		/// <returns></returns>
		public static decimal GetDecimal(this DataRow row, int columnIndex) {
			return Get<decimal>(row, columnIndex);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="row"></param>
		/// <param name="columnIndex"></param>
		/// <returns></returns>
		public static double GetDouble(this DataRow row, int columnIndex) {
			return Get<double>(row, columnIndex);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="row"></param>
		/// <param name="columnIndex"></param>
		/// <returns></returns>
		public static bool GetBoolean(this DataRow row, int columnIndex) {
			return Get<bool>(row, columnIndex);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="row"></param>
		/// <param name="columnIndex"></param>
		/// <returns></returns>
		public static DateTime GetDateTime(this DataRow row, int columnIndex) {
			return Get<DateTime>(row, columnIndex);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="table"></param>
		/// <param name="writer"></param>
		public static void DumpSchema(this DataTable table, System.IO.TextWriter writer) {
			System.Diagnostics.Debug.Assert(writer != null);

			if (table == null) {
				writer.WriteLine("<null>");
				return;
			}

			writer.WriteLine("{0,32}|{1,12}", "Column Name", "Type");
			writer.WriteLine("---------------------------------------------------------------------------------");
			foreach (DataColumn col in table.Columns) {
				writer.WriteLine("{0,32}|{1,12}", col.ColumnName, col.DataType.Name);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="view"></param>
		/// <param name="writer"></param>
		public static void DumpSchema(this DataView view, System.IO.TextWriter writer) {
			if (view == null) {
				DumpSchema((DataTable)null, writer);
				return;
			}

			DumpSchema(view.Table, writer);
		}
	} // end of DataTableExtensions.
}
